package cn.xlbweb.chat.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * @author: bobi
 * @date: 2019-12-04 22:03
 * @description:
 */
@Component
@Slf4j
public class ChatServer {

    private EventLoopGroup parentGroup;
    private EventLoopGroup childGroup;
    private ServerBootstrap serverBootstrap;
    private ChannelFuture channelFuture;

    /**
     * 1.单例对象
     */
    private static volatile ChatServer instance = null;

    /**
     * 2.构造器私有化
     */
    private ChatServer() {
        parentGroup = new NioEventLoopGroup();
        childGroup = new NioEventLoopGroup();
        serverBootstrap = new ServerBootstrap();
        this.serverBootstrap.group(parentGroup, childGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ChannelPipeline pipeline = ch.pipeline();
                        pipeline.addLast(new HttpServerCodec());
                        pipeline.addLast(new ChunkedWriteHandler());
                        pipeline.addLast(new HttpObjectAggregator(1024 * 64));
                        pipeline.addLast(new WebSocketServerProtocolHandler("/websocket"));
                        pipeline.addLast(new ChatHandler());
                    }
                });
    }

    /**
     * 3.静态的工厂方法
     *
     * @return
     */
    public static ChatServer getInstance() {
        if (instance == null) {
            synchronized (ChatServer.class) {
                if (instance == null) {
                    instance = new ChatServer();
                }
            }
        }
        return instance;
    }

    /**
     * 4.启动Websocket服务
     */
    public void start() {
        this.channelFuture = serverBootstrap.bind(8088);
        log.info("Netty Websocket服务启动完成: ws://localhost:{}/websocket", 8088);
    }
}
